package com.cwnu.sw.cys.core.websocket;

import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;

import com.cwnu.sw.cys.core.common.utils.NettyUtil;
import com.cwnu.sw.cys.core.websocket.domain.enums.WSReqTypeEnum;
import com.cwnu.sw.cys.core.websocket.domain.vo.req.WSAuthorizeReq;
import com.cwnu.sw.cys.core.websocket.domain.vo.req.WSBaseReq;
import com.cwnu.sw.cys.core.websocket.service.WebSocketService;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Sharable
public class NettyWebSocketServerHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
    private WebSocketService webSocketService;

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        webSocketService = SpringUtil.getBean(WebSocketService.class);
        log.info("保存channel了");
        Channel channel = ctx.channel();
        webSocketService.connect(channel);
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        userOffline(channel);
        log.info("DEBUG: 用户下线");
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        Channel channel = ctx.channel();

        if(evt instanceof WebSocketServerProtocolHandler.HandshakeComplete){
            webSocketService.connect(channel);
            String token = NettyUtil.getAttr(channel, NettyUtil.TOKEN);
            if(StrUtil.isNotBlank(token))
            {
                webSocketService.authorize(channel,new WSAuthorizeReq(token));
            }
            log.info("握手完成");
        }else if(evt instanceof IdleStateEvent){
            IdleStateEvent event = (IdleStateEvent) evt;
            if(event.state() == IdleState.READER_IDLE){
                log.info("读空闲");
                // TODO 用户下线
                userOffline(channel);
            }
        }
//        else if(evt == WebSocketServerProtocolHandler.ServerHandshakeStateEvent.HANDSHAKE_COMPLETE){
//            log.info("握手完成");
//            Attribute<Object> token =  channel.attr(AttributeKey.valueOf("token"));
//            webSocketService.authorize(channel,new WSAuthorizeReq(token.get().toString()));
//        }
        super.userEventTriggered(ctx, evt);
}

    private void userOffline(Channel channel) {
        webSocketService.remove(channel);
        channel.close();
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
        String text = msg.text();
        //log.info(text);
        WSBaseReq req = JSONUtil.toBean(text, WSBaseReq.class);
        WSReqTypeEnum wsReqTypeEnum = WSReqTypeEnum.of(req.getType());
        System.out.println(wsReqTypeEnum);
        Channel channel = ctx.channel();
        switch (wsReqTypeEnum){
            case AUTHORIZE:
                webSocketService.authorize(channel,new WSAuthorizeReq(req.getData()));
                //SpringUtil.getBean(WebSocketService.class).authorize(ctx,req);
                break;
            case HEARTBEAT:
                //ctx.channel().writeAndFlush(new TextWebSocketFrame("{\"type\":2}"));
                break;
            case LOGIN:
                //SpringUtil.getBean(WebSocketService.class).login(ctx,req);
                webSocketService.handleLoginReq(channel,req);
                log.info("请求二维码");
                // ctx.channel().writeAndFlush(new TextWebSocketFrame("{\"type\":1,\"data\":\"https://www.baidu.com\"}"));
                break;
            default:
                log.info("未知请求");
                break;
        }
    }

    /**
     * @param ctx
     * @param cause
     * @throws Exception
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        log.info("exceptionCaught",cause);
        super.exceptionCaught(ctx, cause);
    }
}
